import $ from 'jquery'
import defaultValue from "./defaultValue.js";

/**
 * 工具类
 *createUrlTemplateImageryProvider
 * @alias Core
 * @constructor
 *
 */
function Core() {

}

/**
 * 获取默认值。
 *
 * @param {*} a
 * @param {*} b
 * @returns {*} 如果未定义，则返回第一个参数，否则返回第二个参数
 *
 * @example
 * param = sgworld.Core.defaultValue(param, 'default');
 */
Core.prototype.defaultValue = function (a, b) {
  return defaultValue(a, b);
}

/**
 * 随机id
 * @returns {String} 返回一个随机id
 * @example
 * id = sgworld.Core.createRandomId();
 */
Core.prototype.createRandomId = function () {
  return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
}

/**
 * 修改鼠标样式。
 *
 * @param {DOM} container html DOM节点
 * @param {Number} [cursorstyle=0] 鼠标类型（0为默认，1为使用cur图标）
 * @param {String} url cur图标路径。
 *
 * @example
 * sgworld.Core.mouse(Viewer.container, 1, 'draw.cur');
 */
Core.prototype.mouse = function (container, cursorstyle, url) {
  if (cursorstyle == 1) {
    container.style.cursor = "url(" + url + "),auto";
  } else {
    container.style.cursor = "default";
  }
}

/**
 * 创建鼠标Tooltip提示框。
 *
 * @param {*} [styleOrText] 提示框样式或文本内容
 * @param {String} [styleOrText.origin='center'] 对齐方式(center/top/bottom)
 * @param {String} [styleOrText.color='black'] 提示框颜色(black/white/yellow)
 * @param {String} [styleOrText.id=undefined] 提示框唯一id(可选)
 * @param {Object} position 显示位置
 * @param {Boolean} show 是否显示(如果为true，styleOrText必须为显示的文本内容)
 * @returns {Tooltip} Tooltip提示框。
 *
 * @example
 * sgworld.Core.CreateTooltip('这里是提示信息', {x:500, y:500}, true);
 * 或
 * tooltip = sgworld.Core.CreateTooltip();
 * tooltip.showAt({x:500, y:500}, '这里是提示信息');
 * 
 * tooltip.show(false); //隐藏提示框
 * tooltip.show(true); //显示提示框
 */
Core.prototype.CreateTooltip = function (styleOrText = {}, position, show) {
  var style, _x, _y, _color, id;
  if (typeof styleOrText === 'object') {
    style = styleOrText;
  }
  if (style && style.origin) {
    style.origin === 'center' && (_x = 15, _y = -12)
    style.origin === 'top' && (_x = 15, _y = -44)
    style.origin === 'bottom' && (_x = 15, _y = 20)
  } else {
    _x = 15, _y = 20;
  }
  if (style && style.color) {
    style.color === 'white' && (_color = 'background: rgba(255, 255, 255, 0.8);color: black;')
    style.color === 'black' && (_color = 'background: rgba(0, 0, 0, 0.5);color: white;')
    style.color === 'yellow' && (_color = 'color: black;background-color: #ffcc33;border: 1px solid white;')
  } else {
    _color = 'background: rgba(0, 0, 0, 0.5);color: white;'
  }
  if (style && style.id) {
    id = "toolTip" + style.id;
  } else {
    id = "toolTip";
  }

  var tooltip = document.getElementById(id);

  if (!tooltip) {
    var elementbottom = document.createElement("div");
    $(".cesium-viewer").append(elementbottom);
    var html = '<div id="' + id + '" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' + _color + '"></div>';
    $('.cesium-viewer').append(html);
    tooltip = document.getElementById(id);
  }
  if (show) {
    tooltip.innerHTML = styleOrText;
    tooltip.style.left = position.x + _x + "px";
    tooltip.style.top = position.y + _y + "px";
    tooltip.style.display = "block";
  } else {
    tooltip.style.display = "none";
  }
  return {
    tooltip: tooltip,
    style: style,
    showAt: function (position, text) {
      this.tooltip.innerHTML = text;
      if (this.style && this.style.origin) {
        this.style.origin === 'center' && (_x = 15, _y = -this.tooltip.offsetHeight / 2);
        this.style.origin === 'top' && (_x = 15, _y = -this.tooltip.offsetHeight - 20);
        this.style.origin === 'bottom' && (_x = 15, _y = 20)
      } else {
        _x = 15, _y = -this.tooltip.offsetHeight / 2;
      }
      this.tooltip.style.left = position.x + _x + "px";
      this.tooltip.style.top = position.y + _y + "px";
      this.tooltip.style.display = "block";
    },
    show: function (show) {
      if (show) {
        this.tooltip.style.display = "block";
      } else {
        this.tooltip.style.display = "none";
      }
    }
  };
}

/**
 *
 * 创建结果提示框
 * @param {Viewer} [Viewer] 地图视图
 * @param {Object} [style] 样式
 * @param {String} [style.id=undefined] 提示框唯一id(可选)
 * @param {String} [style.color='yellow'] 提示框颜色(black/white/yellow/blue)
 * @param {Number} [style.addX=0] 提示框X方向偏移量
 * @param {Number} [style.addY=0] 提示框Y方向偏移量
 * @param {Number} [style.near=undefined] 提示框最小可视距离
 * @param {Number} [style.far=undefined] 提示框最大可视距离
 * 
 * @returns {ResultTooltip} ResultTooltip提示框。
 * @example
 * tooltip = sgworld.Core.CreateResultTooltip(Viewer);
 * tooltip.showAt(Cesium.Cartesian3.fromDegrees(110, 30, 10), '这里是提示信息');
 * 
 * tooltip.show(false); //隐藏提示框
 * tooltip.show(true); //显示提示框
 */
Core.prototype.CreateResultTooltip = function (Viewer, style = {}) {
  var _x, _y, _color;
  let toolId = style.id ? 'resultToolTip' + style.id : 'resultToolTip';
  var tooltip = document.getElementById(toolId);

  if (style.color) {
    style.color === 'white' && (_color = 'background: rgba(255, 255, 255, 0.8);color: black;')
    style.color === 'black' && (_color = 'background: rgba(0, 0, 0, 0.5);color: white;')
    style.color === 'blue' && (_color = 'background: rgba(48, 119, 221);color: white;')
    style.color === 'yellow' && (_color = 'color: black;background-color: #ffcc33;border: 1px solid white;')
  } else {
    _color = 'color: black;background-color: #ffcc33;border: 1px solid white;';
  }
  if (!tooltip) {
    var html = '<div id="' + toolId + '" class="resultToolTip" style="display: none;pointer-events: none;position: absolute;z-index: 1000;opacity: 0.8;border-radius: 4px;padding: 4px 8px;white-space: nowrap;font-family:黑体;color:white;font-weight: bolder;font-size: 14px;' + _color + '"></div>';
    $(Viewer.container).append(html);
    tooltip = document.getElementById(toolId);
  }
  var addX = style.addX || 0;
  var addY = style.addY || 0;
  var position;
  var _this = this;
  if (style.closeBtn) {
    tooltip.className = 'resultToolTip resultToolTipClose';
    tooltip.onclick = () => {
      tooltip.style.display = "none";
      position = undefined;
    }
  }

  function updateHtmlPosition() {
    if (position) {
      if (style.far !== undefined || style.near !== undefined) {
        let distance = _this.getPointToCameraDistance(Viewer, position)
        if (distance > style.far) {
          tooltip.style.display = "none";
          return;
        } else if (distance < style.near) {
          tooltip.style.display = "none";
          return;
        } else {
          tooltip.style.display = "block";
        }
      }
      var CanvasCoordinates = Viewer.scene.cartesianToCanvasCoordinates(position);
      if (!CanvasCoordinates) return;
      _x = -tooltip.offsetWidth / 2 + addX;
      _y = -tooltip.offsetHeight + addY;
      tooltip.style.left = CanvasCoordinates.x + _x + "px";
      tooltip.style.top = CanvasCoordinates.y + _y + "px";
    }
  }
  //监听视角改变
  Viewer.clock.onTick.addEventListener(updateHtmlPosition);
  return {
    tooltip: tooltip,
    position: position,
    showAt: function (_position, text) {
      this.tooltip.innerHTML = text;
      this.tooltip.style.display = "block";
      this.position = _position;
      position = _position;
      if (position) {
        var CanvasCoordinates = Viewer.scene.cartesianToCanvasCoordinates(position);
        if (!CanvasCoordinates) return;
        _x = -this.tooltip.offsetWidth / 2 + addX;
        _y = -this.tooltip.offsetHeight + addY;
        this.tooltip.style.left = CanvasCoordinates.x + _x + "px";
        this.tooltip.style.top = CanvasCoordinates.y + _y + "px";
      }
    },
    show: function (show) {
      if (show) {
        this.tooltip.style.display = "block";
        position = this.position;
      } else {
        this.tooltip.style.display = "none";
        position = undefined;
      }
    },
    destroy() {
      Viewer.clock.onTick.removeEventListener(updateHtmlPosition);
      tooltip.remove();
    }
  };
}

/**
 * 生成任意字符串
 * @returns {String}
 */
Core.prototype.getuid = function () {
  // var idStr = Date.now().toString(36);
  // idStr += Math.random().toString(36).substr(3);
  // return idStr;

  // return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
  //     var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
  //     return v.toString(16);
  // });

  return this.uuid(8, 16);
}

/**
 * 获取uuid
 */
Core.prototype.uuid = function (len, radix) {
  var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
  var uuid = [],
    i;
  var uuid = [],
    i;
  radix = radix || chars.length;

  if (len) {
    // Compact form
    for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
  } else {
    // rfc4122, version 4 form
    var r;

    // rfc4122 requires these characters
    uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
    uuid[14] = '4';

    // Fill in random data.  At i==19 set the high bits of clock sequence as
    // per rfc4122, sec. 4.1.5
    for (i = 0; i < 36; i++) {
      if (!uuid[i]) {
        r = 0 | Math.random() * 16;
        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
      }
    }
  }

  return uuid.join('');
}

Core.prototype.isnull = function (param) {
  if (param == null || param == undefined || param === '')
    return true;
  else
    return false;
}

/**
 * 判断是否是颜色
 */
Core.prototype.isHtmlColor = function (htmlcolor) {
  var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/;
  return reg.test(htmlcolor);
}

//使用时间进行命名
Core.prototype.getTimeName = function () {
  const now = new Date()
  const yyyy = now.getFullYear()
  const MM = now.getMonth() + 1 > 9 ? now.getMonth() + 1 : `0${now.getMonth() + 1}`
  const DD = now.getDate() > 9 ? now.getDate() : `0${now.getDate()}`
  const HH = now.getHours() > 9 ? now.getHours() : `0${now.getHours()}`
  const mm = now.getMinutes() > 9 ? now.getMinutes() : `0${now.getMinutes()}`
  const ss = now.getSeconds() > 9 ? now.getSeconds() : `0${now.getSeconds()}`
  return `${yyyy}${MM}${DD}${HH}${mm}${ss}`
}

/**
 * 数据数组去重
 * @param {Array} arr 数组
 * @returns {Promise.<Object>}新的数组
 */
Core.prototype.unique = function (arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i])
    }
  }
  return newArr
}
/**
 * 对象参数合并
 * @param {Object} o 对象
 * @param {Object} n 被合并的对象
 * @param {Boolean} [override=false] 是否覆盖原属性值
 * @param {Boolean} [mergeTheSame=false] 是否只合并相同属性
 */
Core.prototype.extend = function (o, n, override = false, mergeTheSame = false) {
  for (var key in n) {
    if (mergeTheSame) {
      if (o.hasOwnProperty(key)) {
        o[key] = n[key];
      }
    } else {
      if (!o.hasOwnProperty(key) || override) {
        o[key] = n[key];
      }
    }
  }
  return o;
}

/**
 * 坐标偏移
 * @param {Cartesian3} position 坐标
 * @param {Cartesian3} offset 偏移大小
 * @param {HeadingPitchRoll} headingPitchRoll 旋转
 * @returns {Cartesian3}
 */
Core.prototype.setPositionOffset = (position, offset, headingPitchRoll) => {
  // Matrix4
  let frompoint_to_world_matrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, headingPitchRoll || new Cesium.HeadingPitchRoll());

  // 向position为原点，正北为y，正东为x，地心朝上为z分别平移
  // let offset = new Cesium.Cartesian3(10, 6, 2);

  let result = new Cesium.Cartesian3(0, 0, 0)
  // 转换矩阵左乘局部平移向量，结果是世界坐标下的平移终点向量
  Cesium.Matrix4.multiplyByPoint(frompoint_to_world_matrix, offset, result)
  return result
}

/**
 * 获取影像偏移的切片方案
 * @param {String} [srs="GCJ02"] 坐标系
 */
Core.prototype.getOffsetTilingScheme = function (srs = "GCJ02") {
  let TilingScheme, projection
  if (srs === 'GCJ02') {
    TilingScheme = new Cesium.WebMercatorTilingScheme();
    projection = new Cesium.WebMercatorProjection();
    TilingScheme._projection.project = function (cartographic, result) {
      result = CoordTransform.WGS84ToGCJ02(
        Cesium.Math.toDegrees(cartographic.longitude),
        Cesium.Math.toDegrees(cartographic.latitude)
      );
      result = projection.project(
        new Cesium.Cartographic(
          Cesium.Math.toRadians(result[0]),
          Cesium.Math.toRadians(result[1])
        )
      );
      return new Cesium.Cartesian2(result.x, result.y);
    };
    TilingScheme._projection.unproject = function (cartesian, result) {
      let cartographic = projection.unproject(cartesian);
      result = CoordTransform.GCJ02ToWGS84(
        Cesium.Math.toDegrees(cartographic.longitude),
        Cesium.Math.toDegrees(cartographic.latitude)
      );
      return new Cesium.Cartographic(
        Cesium.Math.toRadians(result[0]),
        Cesium.Math.toRadians(result[1])
      );
    };
  }
  return TilingScheme;
}

/**
 * 空间距离测量用米
 * @param {Object} positions 坐标集合
 * @param {Object} Cesium 
 */
Core.prototype.getSpaceDistancem = function (positions, Cesium) {
  var distance = 0;
  for (var i = 0; i < positions.length - 1; i++) {
    var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
    var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
    /**根据经纬度计算出距离**/
    var geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(point1cartographic, point2cartographic);
    var s = geodesic.surfaceDistance;
    //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
    //返回两点之间的距离
    s = (Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)));
    distance = distance + s;
  }
  return distance.toFixed(2);
}

/**
 * 计算空间两点之间的俯仰角
 * @param {Object} p1 起始点
 * @param {Object} p2 结束点
 */
Core.prototype.ElevationAngle = function (p1, p2, Cesium) {
  //空间距离测量
  function getSpaceDistance(positions, Cesium) {
    var distance = 0;
    for (var i = 0; i < positions.length - 1; i++) {
      var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
      var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
      /**根据经纬度计算出距离**/
      var geodesic = new Cesium.EllipsoidGeodesic();
      geodesic.setEndPoints(point1cartographic, point2cartographic);
      var s = geodesic.surfaceDistance;
      //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
      //返回两点之间的距离
      s = (Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)));
      distance = distance + s;
    }
    return distance;
  }

  //水平距离测量
  function getHorizontalDistance(positions, Cesium) {
    var distance = 0;
    for (var i = 0; i < positions.length - 1; i++) {

      var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]);
      var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);
      /**根据经纬度计算出距离**/
      var geodesic = new Cesium.EllipsoidGeodesic();
      geodesic.setEndPoints(point1cartographic, point2cartographic);
      var s = geodesic.surfaceDistance;
      //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2)));
      //返回两点之间的距离
      //s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2));
      distance = distance + s;
    }
    return distance;
  }

  //获取高度
  function getHeight(_positions, Cesium) {
    try {
      if (_positions.length > 1) {
        var cartographic = Cesium.Cartographic.fromCartesian(_positions[0]);
        var cartographic1 = Cesium.Cartographic.fromCartesian(_positions[1]);
        var height_temp = (cartographic1.height - cartographic.height);
        //var height_temp = _positions[1].z - _positions[0].z;
        return height_temp;
      } else {
        return 0;
      }
    } catch (ex) {
      console.log(ex);
    }

  }

  var cartographic = Cesium.Cartographic.fromCartesian(p1);
  var cartographic1 = Cesium.Cartographic.fromCartesian(p2);
  var height = cartographic.height - (cartographic.height - cartographic1.height);
  var p3 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic1.longitude), Cesium.Math.toDegrees(cartographic1.latitude), cartographic.height);

  var c = parseFloat(getSpaceDistance([p1, p2], Cesium));
  var a = parseFloat(getHorizontalDistance([p1, p3], Cesium));
  var b = parseFloat(getHeight([p3, p2], Cesium));
  var sinb = b / c;
  var angle = Math.asin(sinb) * 180 / 3.14;
  return angle;
}

/**
 * 两点方位角
 * @param {number} lon1 起点经度
 * @param {number} lat1 起点纬度
 * @param {number} lon2 终点经度
 * @param {number} lat2 终点纬度
 */
Core.prototype.TwoPointAzimuth = function (lon1, lat1, lon2, lat2) {
  var result = 0.0;
  var getRad = function (d) {
    return d * Math.PI / 180.0;
  };

  var ilat1 = Math.round(0.50 + lat1 * 360000.0);
  var ilat2 = Math.round(0.50 + lat2 * 360000.0);
  var ilon1 = Math.round(0.50 + lon1 * 360000.0);
  var ilon2 = Math.round(0.50 + lon2 * 360000.0);

  lat1 = getRad(lat1);
  lon1 = getRad(lon1);
  lat2 = getRad(lat2);
  lon2 = getRad(lon2);

  if ((ilat1 === ilat2) && (ilon1 === ilon2)) {
    return result;
  } else if (ilon1 === ilon2) {
    if (ilat1 > ilat2)
      result = 180.0;
  } else {
    var c = Math.acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos((lon2 - lon1)));
    var A = Math.asin(Math.cos(lat2) * Math.sin((lon2 - lon1)) / Math.sin(c));
    result = A * 180 / Math.PI;
    if ((ilat2 > ilat1) && (ilon2 > ilon1)) {} else if ((ilat2 < ilat1) && (ilon2 < ilon1)) {
      result = 180.0 - result;
    } else if ((ilat2 < ilat1) && (ilon2 > ilon1)) {
      result = 180.0 - result;
    } else if ((ilat2 > ilat1) && (ilon2 < ilon1)) {
      result += 360.0;
    }
  }
  return result;
}

// 判断是否为手机浏览器
Core.prototype.getBrowser = function () {
  var ua = navigator.userAgent.toLowerCase();
  var btypeInfo = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0];
  if ((ua.match(/msie|trident/g) || [])[0]) {
    btypeInfo = "msie";
  }
  var pc = "";
  var prefix = "";
  var plat = "";
  //如果没有触摸事件 判定为PC
  var isTocuh = ("ontouchstart" in window) || (ua.indexOf("touch") !== -1) || (ua.indexOf("mobile") !== -1);
  if (isTocuh) {
    if (ua.indexOf("ipad") !== -1) {
      pc = "pad";
    } else if (ua.indexOf("mobile") !== -1) {
      pc = "mobile";
    } else if (ua.indexOf("android") !== -1) {
      pc = "androidPad";
    } else {
      pc = "pc";
    }
  } else {
    pc = "pc";
  }
  switch (btypeInfo) {
    case "chrome":
    case "safari":
    case "mobile":
      prefix = "webkit";
      break;
    case "msie":
      prefix = "ms";
      break;
    case "firefox":
      prefix = "Moz";
      break;
    case "opera":
      prefix = "O";
      break;
    default:
      prefix = "webkit";
      break
  }
  plat = (ua.indexOf("android") > 0) ? "android" : navigator.platform.toLowerCase();
  return {
    version: (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], //版本
    plat: plat, //系统
    type: btypeInfo, //浏览器
    pc: pc,
    prefix: prefix, //前缀
    isMobile: (pc == "pc") ? false : true //是否是移动端
  };
}

/**
 * 三维笛卡尔坐标转经纬度
 * @param {Cartesian3} cartesian 三维笛卡尔坐标
 * @returns {Object}
 *
 * @example
 * degrees = sgworld.Core.toDegrees(position');
 */
Core.prototype.toDegrees = function (cartesian) {
  let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  return {
    lon: Cesium.Math.toDegrees(cartographic.longitude),
    lat: Cesium.Math.toDegrees(cartographic.latitude),
    height: cartographic.height
  };
};

export default Core;
